//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <mantle.h>
#include <core.h>
#include "mutex.h"

typedef void        (*ctor_t)();

#if defined(_EVC)
#pragma data_seg(".CRT$XCA", "DATA")
EXTERN_C ctor_t __xc_a[] = { 0 };                    /* C++ initializers */

#pragma data_seg(".CRT$XCZ", "DATA")
EXTERN_C ctor_t __xc_z[] = { 0 };
#endif

DECL_LINKERSYMBOL ctor_t _GlobalCtorBegin;
DECL_LINKERSYMBOL ctor_t _GlobalCtorEnd;

EXTERN_C DECL_CODEINIT void CDECL SetupCRT()
{
#if defined(_GNUC)
    for (ctor_t *pCtor = &_GlobalCtorBegin;
        pCtor < &_GlobalCtorEnd; pCtor++) {
        (*pCtor)();
    }
#elif defined(_EVC)
    for (ctor_t *pCtor = __xc_a; pCtor < __xc_z; pCtor++) {
        if (NULL != *pCtor) {
            (**pCtor)();
        }
    }
#else
#error unknown compiler
#endif
}

EXTERN_C ECode __stdcall CrtFindService(WString wszName, IInterface **ppObj)
{
    return DzFindService(wszName, ppObj);
}

EXTERN_C ECode __stdcall CrtGetBootModule(const wchar_t *wszName,
    UInt32 *puAddr, UInt32 *puSize)
{
    return _DzGetBootModule(wszName, puAddr, puSize);
}

EXTERN_C ECode CrtInitializeLock(PVoid* ppLock)
{
	IMutex *pLock = new CMutex();
    if (pLock == NULL) {
        return E_OUT_OF_MEMORY;
    }

	*ppLock = pLock;

    return NOERROR;
}

EXTERN_C ECode CrtEnterLock(PVoid pLock)
{
	if (pLock == NULL)
		return E_INVALID_OPERATION;

    WaitResult wr;
    IMutex *lock = (IMutex*)pLock;

    return lock->Lock(&wr);
}

EXTERN_C ECode CrtLeaveLock(PVoid pLock)
{
	if (pLock == NULL)
		return E_INVALID_OPERATION;

    IMutex *lock = (IMutex*)pLock;
    return lock->Unlock();
}

EXTERN_C ECode CrtDeleteLock(PVoid* ppLock)
{
	if (!ppLock || !(*ppLock))
		return E_INVALID_OPERATION;

    IMutex *pLock = (IMutex*)(*ppLock);
    pLock->Release();
    *ppLock= NULL;

	return NOERROR;
}

EXTERN_C ECode /* IApplet* */ __stdcall CrtGetCurrentAppletDir(WStringBuf* pwsAppletDir)
{
    uint_t uStackTop = ::GetCurrentThread()->m_uUserStackBase + USER_STACK_SIZE
            - USER_STACK_PRESERVED_SIZE;

    PVoid pTlsValue = *((PInterface *)(uStackTop + USER_STACK_PRESERVED_SIZE)
        + (TL_APPLET_DIR_SLOT - TLS_TOTAL_SLOTS));

    if (pTlsValue == NULL) return E_DOES_NOT_EXIST;

    pwsAppletDir->Copy((wchar_t*)pTlsValue);

    return NOERROR;
}
